home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / presto / presto10.lha / src / locks.C < prev    next >
C/C++ Source or Header  |  1991-12-11  |  4KB  |  238 lines

  1. /*
  2.  * locks.c
  3.  *    Definitions some derived synchro classes
  4.  *
  5.  */
  6.  
  7.  
  8. #define _LOCKS_C
  9.  
  10. #include "presto.h"
  11. #include "locks.h"
  12.  
  13.  
  14.  
  15. Lock::Lock(char *name)    : SynchroObject    (OBJ_LOCK, name)
  16. {
  17.     lo_owner = 0;
  18. }
  19.  
  20. Lock::Lock(char *name, int locktype)    : SynchroObject (locktype, name)
  21. {
  22.     lo_owner = 0;
  23. }
  24.  
  25.  
  26. Lock::~Lock()
  27. {
  28.     if (lo_owner)
  29.         error("Can't delete a held lock!");
  30. }
  31.  
  32.  
  33.  
  34. //
  35. // Threads are given ownership of the lock on ENTRY iff there
  36. // is no current owner.  On EXIT, we just clear the owner field
  37. // and wakeup the first guy on the queue.
  38. // Inline version falls through to lock if the lock is already
  39. // held.  This optimizes entry for non-occupied routines.
  40. //
  41. void
  42. Lock::lock()
  43. {
  44.     SynchroObject::lock();
  45.     if (lo_owner == 0)    {
  46.         lo_owner = thisthread;
  47.         SynchroObject::unlock();
  48.     } else
  49.         lock2();
  50. }
  51.  
  52.  
  53. void
  54. Lock::unlock()
  55. {
  56.     SynchroObject::lock();
  57.     if (thisthread != lo_owner)
  58.         error("Can't release someone else's lock");
  59.  
  60.     lo_owner = 0;
  61.     Thread *newowner = recall();    // find new lock owner
  62.     //
  63.     // Dont guarantee fairness
  64.     //
  65.     SynchroObject::unlock();
  66.     if (newowner)
  67.         newowner->wakeup((SynchroObject*)this);
  68. }
  69.  
  70.  
  71.  
  72. //
  73. // Secondary looping entry point for a lock
  74. //
  75. void
  76. Lock::lock2()
  77. {
  78.     if (thisthread->flags()&TF_SCHEDULER)
  79.         error("Can't block a scheduler thread!");
  80.     
  81.     // expect lock to be held on the way in
  82.     for (;;)    {
  83.         if (lo_owner == 0)
  84.             break;
  85.         remember(thisthread);
  86.         SynchroObject::unlock();
  87.         thisthread->sleep(this);
  88.         SynchroObject::lock();
  89.     }
  90.     lo_owner = thisthread;
  91.     SynchroObject::unlock();
  92. }
  93.  
  94. void
  95. Lock::print(ostream& s)
  96. {
  97.     s << "Lock:";
  98.     SynchroObject::print(s);
  99.     s << form(" lo_owner=0x%x", lo_owner);
  100. }
  101.  
  102.  
  103. Monitor::Monitor(char* name) :    Lock (name, OBJ_MONITOR)
  104. {
  105. }
  106.  
  107. Monitor::~Monitor()
  108. {
  109.     if (owner())
  110.         error("can't delete a held monitor");
  111. }
  112.  
  113. void
  114. Monitor::print(ostream& s)
  115. {
  116.     s << "Monitor:";
  117.     Lock::print(s);
  118. }
  119.  
  120.  
  121. //
  122. // Condition variables are bound to monitors.  If you run a condition
  123. // variable UNBOUND, and you do not guarantee that operations on the
  124. // condition variable are atomic (locked), bad things will happen.
  125. // Condition variables assume that they will only be referenced
  126. // from within a monitor, so they don't bother to lock their data
  127. // structures when referenced.
  128. //
  129.  
  130. Condition::Condition(char *name) : SynchroObject (OBJ_CONDVAR, name)
  131. {    
  132.     cerr << "Warning: use of unbound condition variable " << name << 
  133.         " is not advised\n";
  134.     co_monitor = 0;
  135. }
  136.  
  137. Condition::Condition(Monitor* boundmon) : SynchroObject (OBJ_CONDVAR,0)
  138. {
  139.     co_monitor = boundmon;
  140. }
  141.  
  142. Condition::Condition(Monitor &boundmon) : SynchroObject (OBJ_CONDVAR, 0)
  143. {
  144.     co_monitor = &boundmon;
  145. }
  146.  
  147. Condition::Condition(Monitor* boundmon, char* name) : SynchroObject (OBJ_CONDVAR,name)
  148. {
  149.     co_monitor = boundmon;
  150. }
  151.  
  152. Condition::Condition(Monitor& boundmon, char* name) : SynchroObject (OBJ_CONDVAR, name)
  153. {
  154.     co_monitor = &boundmon;
  155. }
  156.  
  157.  
  158. Condition::~Condition()
  159. {
  160. }
  161.  
  162.  
  163. //
  164. // Signal a condition variable.  Backlogs probably will not get 
  165. // implemented because they may have nasty overtones.
  166. // No locking needed since we assume we are inside monitored region
  167. //
  168. void
  169. Condition::broadcast()
  170. {
  171.     Thread    *t;
  172.  
  173.     if (!threadok())    
  174.         error("Condition broadcast by non-owning thread!");
  175.     
  176.     while (t = waitingQueue()->get())    {    // DO NOT LOCK
  177.         t->wakeup(this);
  178.     }
  179. }
  180.  
  181. //
  182. // No locking here either
  183. //
  184. void
  185. Condition::signal()
  186. {
  187.     if (!threadok())    
  188.         error("Condition signal by non-owning thread!");
  189.     Thread *t = waitingQueue()->get();        // DO NOT LOCK
  190.     if (t)
  191.         t->wakeup(this);
  192. }
  193.  
  194. //
  195. // Put a thread to sleep on a condition variable.
  196. //  Get the monitor which we currently hold and exit it.
  197. //
  198. // We must be responsible for remembering threads which need to
  199. // be reawoken on an event of this condition.  If we relied on
  200. // the sleep routines, it is possible that we could wakeup someone
  201. // up, have them start running, and signal us, yet we have not been
  202. // remembered since our sleep call hadn't yet gotten far enough.
  203. //
  204. // No locking here also
  205. //
  206. void
  207. Condition::wait()
  208. {
  209.     if (!threadok())    
  210.         error("Condition wait by non-owning thread!");
  211.     remember(thisthread);    // will NOT lock the queue
  212.     if (co_monitor)    {        // release the monitor
  213.         co_monitor->exit();
  214.     }
  215.     thisthread->sleep(this);
  216.     
  217.     // reaquire the monitor if we gave it up
  218.     if (co_monitor)    {
  219.         co_monitor->entry();
  220.     }
  221. }
  222.  
  223.  
  224.  
  225. void
  226. Condition::print(ostream& s)
  227. {
  228.     s << "Condition:";
  229.     SynchroObject::print(s);
  230.     s << " bound ";
  231.     if  (co_monitor)
  232.         s << co_monitor;
  233.     else
  234.         s << "_unbound_";
  235. }
  236.        
  237.  
  238.